package org.example;

import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.WString;
import com.sun.jna.ptr.IntByReference;
import org.example.library.WintunExtensionLibrary;
import org.example.library.WintunLibrary;
import org.example.util.WindowsDnsManager;
import org.pcap4j.packet.IpPacket;
import org.pcap4j.packet.IpSelector;
import org.pcap4j.packet.TcpPacket;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class ProxyMain {

    public static void main(String[] args) throws Exception {

        String name = "Test";
        String tunnelType = "Wintun";
        //创建网络适配器
        Pointer adapterHandle = WintunLibrary.INSTANCE.WintunCreateAdapter(new WString(name), new WString(tunnelType), null);

        if (adapterHandle == null) {
            throw new RuntimeException("网络适配器创建失败！(可能是没用管理员启动)");
        }

        String hostAddress = "172.40.1.1";
        //设置网络设配器ip 和 子网掩码
        WintunExtensionLibrary.INSTANCE.CreateAddressRow(adapterHandle,hostAddress,16);

        //启动适配器
        Pointer sessionHandle = WintunLibrary.INSTANCE.WintunStartSession(adapterHandle, 0x400000);

        //虚拟线程
        ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();

        //创建dns
        String ipv4 = "127.0.0.1";
        String ipv6 = "::1";
        SimpleDnsServer ssV4 = new SimpleDnsServer(ipv4,hostAddress);
        executor.submit(ssV4);

        SimpleDnsServer ssV6 = new SimpleDnsServer(ipv6,hostAddress);
        executor.submit(ssV6);
        //修改dns
        WindowsDnsManager.setManualDNSv4(name, ipv4); // 修改
        WindowsDnsManager.setManualDNSv6(name, ipv6); // 修改
        //刷新dns缓存
        WindowsDnsManager.flushDns();


        // 注册关闭钩子，程序结束自动还原 DNS
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            try {
                WindowsDnsManager.setAutoDNSv4(name);
                WindowsDnsManager.setAutoDNSv6(name);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }));

        TcpHandler tcpSocket = new TcpHandler(sessionHandle);
        while (true){

            //读取适配器数据包
            IntByReference incomingPacketSize = new IntByReference();
            Pointer incomingPacket = WintunLibrary.INSTANCE.WintunReceivePacket(sessionHandle, incomingPacketSize);

            if (incomingPacket != null) {
                try {
                    int packetSize = incomingPacketSize.getValue();
                    byte[] packetBytes = incomingPacket.getByteArray(0, packetSize);

                    //解析数据包
                    IpPacket packet = (IpPacket) IpSelector.newPacket(packetBytes, 0, packetBytes.length);
//                    System.out.println(packet);

                    if(packet.getPayload() instanceof TcpPacket){
                        tcpSocket.parsePacket(packet);
                    }

                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    WintunLibrary.INSTANCE.WintunReleaseReceivePacket(sessionHandle, incomingPacket);
                }


            } else {

                int lastError = Native.getLastError();
                if (lastError == 0x103) {
                    //没数据等待数据
                    Pointer readWaitEvent = WintunLibrary.INSTANCE.WintunGetReadWaitEvent(sessionHandle);
                } else {
                    WintunLibrary.INSTANCE.WintunCloseAdapter(sessionHandle);
                    throw new RuntimeException("数据包读取失败，错误码："+lastError);
                }
            }

        }
    }

}